// Serialize Stream
// (c) jimon game studio

#include "CSerializeStream.h"

namespace je
{
	namespace core
	{
		//! Constructor
		CSerializeStream::CSerializeStream()
			:CurrentLinearMode(false)
		{
			JENEW(CurrentSection,jeSerializeStreamSection(0,NULL,0))
		}

		//! Destructor
		CSerializeStream::~CSerializeStream()
		{
			if(CurrentSection)
				JEDELETE(CurrentSection)
		}
		
		//! Set Mode
		void CSerializeStream::SetMode(SerializeStreamMode StreamMode)
		{
			CurrentStreamMode = StreamMode;
		}

		//! Get Mode
		SerializeStreamMode CSerializeStream::GetMode()
		{
			return CurrentStreamMode;
		}

		//! Set Linear Mode
		void CSerializeStream::SetLinearMode(u1 Enabled)
		{
			CurrentLinearMode = Enabled;
			CurrentSection->SetLinearMode(CurrentLinearMode);
		}

		//! Get Linear Mode
		u1 CSerializeStream::GetLinearMode()
		{
			return CurrentLinearMode;
		}

		//! New Section
		void CSerializeStream::NewSection(const MappingHashType & Hash)
		{
			CurrentSection = CurrentSection->OpenSection(Hash,true);
		}

		//! Next Section
		u1 CSerializeStream::NextSection()
		{
			jeSerializeStreamSection * Temp = CurrentSection->GetParent()->NextSection(CurrentSection);
			if(Temp)
			{
				CurrentSection = Temp;
				return true;
			}
			else
				return false;
		}

		//! Open Section
		void CSerializeStream::OpenSection(const MappingHashType & Hash)
		{
			CurrentSection = CurrentSection->OpenSection(Hash);
		}

		//! Close Section
		void CSerializeStream::CloseSection()
		{
			CurrentSection = CurrentSection->CloseSection();
		}

		//! Work With Value
		u1 CSerializeStream::WorkWithValue(const MappingHashType & Hash,void * Value,u32 Size)
		{
			if(CurrentStreamMode == SSM_LOAD)
			{
				void * SourceValue = CurrentSection->GetVariableData(Hash);
				if(SourceValue)
				{
					memcpy(Value,SourceValue,Size);
					return true;
				}
				else
					return false;
			}
			else
			{
				CurrentSection->SetVariable(Hash,Value,Size);
				return true;
			}
		}

		//! Work With Value
		u1 CSerializeStream::WorkWithValue(const MappingHashType & Hash,void ** Value,u32 * Size)
		{
			if(CurrentStreamMode == SSM_LOAD)
			{
				jeSerializeStreamVariable Variable;
				if(CurrentSection->GetVariable(Hash,Variable))
				{
					*Value = CurrentSection->GetData() + Variable.GlobalOffset;
					*Size = Variable.CurrentSize;
					return true;
				}
				else
					return false;
			}
			else
			{
				CurrentSection->SetVariable(Hash,*Value,*Size);
				return true;
			}
		}

		//! Load from buffer
		void CSerializeStream::LoadBuffer(IBuffer * Buffer)
		{
			if(CurrentSection)
				JEDELETE(CurrentSection)
			JENEW(CurrentSection,jeSerializeStreamSection(0,NULL,0))
			Buffer->Lock(BLT_READ);
			Buffer->SetPosition(0);
			Buffer->SaveStreamWorkModeState();
			Buffer->SetStreamWorkMode(true);
			CurrentSection->LoadFromBuffer(Buffer);
			Buffer->RestoreStreamWorkModeState();
			Buffer->UnLock();
		}

		//! Save to buffer
		void CSerializeStream::SaveBuffer(IBuffer * Buffer)
		{
			Buffer->Lock(BLT_WRITE);
			Buffer->Allocate(CurrentSection->GetBufferSize());
			Buffer->SetPosition(0);
			Buffer->SaveStreamWorkModeState();
			Buffer->SetStreamWorkMode(true);
			CurrentSection->SaveToBuffer(Buffer);
			Buffer->RestoreStreamWorkModeState();
			Buffer->UnLock();
		}

		//! Flush Linear Reading
		void CSerializeStream::FlushLinearReading()
		{
			CurrentSection->FlushLinearReading();
		}

		//! Create Serialize Stream
		ISerializeStream * JE_ENGINE_FUNCTION_CALL CreateSerializeStream()
		{
			ISerializeStream * Stream = NULL;
			JENEW(Stream,CSerializeStream)
			return Stream;
		}
	}
}
